--TODO: Remove most of the data from the actual note, keep it in the objectives table. Would save some memory.
--TODO: Add feedback when receiving notes. Will need to use a timer of some sort.


local L = AceLibrary("AceLocale-2.2"):new("Cartographer_QuestObjectives")
local quixote = AceLibrary("Quixote-1.0")
local Dewdrop = AceLibrary("Dewdrop-2.0")
local Tablet = AceLibrary("Tablet-2.0")
local babbleclass = AceLibrary("Babble-Class-2.2")
local BZ = AceLibrary("Babble-Zone-2.2")
local crayon = LibStub("LibCrayon-3.0")
local specialevents_loot = AceLibrary("SpecialEvents-Loot-1.0")
local roster = AceLibrary("Roster-2.1")


local mod = Cartographer:NewModule("Quest Objectives", "AceConsole-2.0", "AceDB-2.0", "AceHook-2.1", "AceEvent-2.0", "AceComm-2.0")
Cart_QO = mod
if AceLibrary:HasInstance("AceDebug-2.0") then
	AceLibrary("AceDebug-2.0"):embed(mod)
	QN = mod
	--QN:SetDebugging(true)
else
	function mod:Debug() end
	--function mod:SetDebugging() end
end

mod:RegisterDB("Cartographer_QuestObjectivesDB", "Cartographer_QuestObjectivesDBPC")

local ICON_NAME = "QuestObjective"
local DB_NAME = "QuestObjectives"
local NOTE_DB_VERSION = 1
local NOTE_DB_COMPAT_VERSION = 1
local QUEST_DB_VERSION = 2
local QUEST_DB_COMPAT_VERSION = 1
local COMM_VERSION = 1

mod.timers = {
	['combat'] = {
		['player'] = 0,
		['party1'] = 0,
		['party2'] = 0,
		['party3'] = 0,
		['party4'] = 0,
	},
	['loot'] = {
		['party1'] = 0,
		['party2'] = 0,
		['party3'] = 0,
		['party4'] = 0,
	},
	['playertrade'] = 0,
	['playerobjective'] = 0,
}
mod.lastobjective = ''

mod.recentnotes = {
}

mod.recentquests = {
}

mod.icon = {
	[ICON_NAME] = {
		text = L["Quest Objective"],
		path = "Interface\\GossipFrame\\AvailableQuestIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-gray'] = {
		text = L["QuestDifficulties"]['gray'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\ActiveQuestIcon_Green",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-green'] = {
		text = L["QuestDifficulties"]['green'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\ActiveQuestIcon_Green",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-yellow'] = {
		text = L["QuestDifficulties"]['yellow'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\ActiveQuestIcon_Orange",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-orange'] = {
		text = L["QuestDifficulties"]['orange'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\ActiveQuestIcon_Orange",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-red'] = {
		text = L["QuestDifficulties"]['red'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\ActiveQuestIcon_Red",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-unknown'] = {
		text = L["ObjectiveTypes"]['unknown'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\BinderGossipIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-item'] = {
		text = L["ObjectiveTypes"]['item'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\VendorGossipIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-object'] = {
		text = L["ObjectiveTypes"]['object'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\BinderGossipIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-monster'] = {
		text = L["ObjectiveTypes"]['monster'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\BattleMasterGossipIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-reputation'] = {
		text = L["ObjectiveTypes"]['reputation'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\BinderGossipIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-event'] = {
		text = L["ObjectiveTypes"]['event'],
		path = "Interface\\AddOns\\Cartographer_QuestObjectives\\Artwork\\BinderGossipIcon",
		width = 14,
		height = 14
	},
}

mod.filter = {
	unknown 	= L["ObjectiveTypes"]['unknown'],
	item     	= L["ObjectiveTypes"]['item'],
	object   	= L["ObjectiveTypes"]['object'],
	monster      	= L["ObjectiveTypes"]['monster'],
--	reputation    	= L["ObjectiveTypes"]['reputation'],
	event      	= L["ObjectiveTypes"]['event'],
}

mod.requests = {
}

function mod:OnInitialize()

	self:RegisterDefaults("profile", {
		filter = {
			unknown  	= true,
			item     	= true,
			object   	= true,
			monster  	= true,
			reputation    	= true,
			event      	= true,
		},
		useObjectiveIcons = true,
		colorIcons = true,
		onlyShowTracked = false,
		hideCompleted = true,
		hideInactive = true,
		showParty = true,
		iconAlpha = 1,
		iconScale = 0.75,
		minimapIcons = true,
		enableSharing = true,
		autoRequest = {
			['*'] = false,
		},
	})

	self:RegisterDefaults("faction", {
		questCount = 0,
		objectives = {
			['*'] = { -- zone
				['*'] = { -- quest
					['*'] = { -- objective
						['notes'] = {},
						['sent'] = {},
					},
				},
			},
		},
		notes = {},
		sources = {
			['*'] = { -- playername
			},
		},
		ignorelist = {
		},
	})

	self:RegisterDefaults("char", {
		questHistory = {}
	})
	
	self:SetCommPrefix("Cartographer-QuestObjectives")
	local memoizations = {
		"REQUEST",
	}
	for zone in BZ:GetIterator() do
		table.insert(memoizations, zone)
	end
	self:RegisterMemoizations(memoizations)
	memoizations = nil

	local aceopts = {
		toggle = {
			name = Cartographer.L["Enabled"],
			desc = Cartographer.L["Suspend/resume this module."],
			type  = 'toggle',
			order = 10,
			get   = function() return Cartographer:IsModuleActive(self) end,
			set   = function() Cartographer:ToggleModuleActive(self) end,
		},
		alpha = {
			name = L["Icon alpha"],
			desc = L["Alpha transparency of the icon"],
			type = 'range',
			min = 0.1,
			max = 1,
			step = 0.05,
			isPercent = true,
			get = "GetIconAlpha",
			set = "SetIconAlpha",
			order = 20
		},
		scale = {
			name = L["Icon size"],
			desc = L["Size of the icons on the map"],
			type = 'range',
			min = 0.5,
			max = 2,
			step = 0.05,
			isPercent = true,
			get = "GetIconScale",
			set = "SetIconScale",
			order = 30
		},
		minimapicons = {
			name = L["Show minimap icons"],
			desc = L["Show quest icons on the minimap"],
			type = 'toggle',
			set = "ToggleShowingMinimapIcons",
			get = "IsShowingMinimapIcons",
			order = 40,
		},
		useobjectiveicons = {
			name = L["Use Objective Icons"],
			desc = L["Use Objective Icons Description"],
			type = 'toggle',
			set = "ToggleUseObjectiveIcons",
			get = "GetUseObjectiveIcons",
			order = 43,
		},
		coloricons = {
			name = L["Color Icons"],
			desc = L["Color Icons Description"],
			type = 'toggle',
			set = "ToggleColorIcons",
			get = "GetColorIcons",
			disabled = function() return self:GetUseObjectiveIcons() end,
			order = 46,
		},
		filter = {
			name = L["Filter"],
			desc = L["Filter out objective types"],
			type = 'group',
			order = 50,
			args = {
				all = {
					name = L["Select all"],
					desc = L["Select all"],
					type = 'execute',
					func = function()
						for k in pairs(self.filter) do
							self:ToggleTypeFilter(k, true)
						end
					end,
					order = 1,
				},
				none = {
					name = L["Select none"],
					desc = L["Select none"],
					type = 'execute',
					func = function()
						for k in pairs(self.filter) do
							self:ToggleTypeFilter(k, false)
						end
					end,
					order = 2,
				},
				blank = {
					type = 'header',
					order = 3,
				}
			}
		},
		sharing = {
			name = L["Note Sharing"],
			desc = L["Note Sharing Description"],
			type = 'group',
			order = 52,
			args = {
				enable = {
					name = L["Enable Sharing"],
					desc = L["Enable Sharing Description"],
					type = 'toggle',
					get = "GetEnableSharing",
					set = "ToggleEnableSharing",
					order = 10,
				},
				autorequest = {
					name = L["Auto Request Notes"],
					desc = L["Auto Request Notes Description"],
					type = 'group',
					pass = true,
					get = "GetAutoRequest",
					set = "ToggleAutoRequest",
					order = 20,
					args = {
						guild = { -- TODO: TESTME
							name = L["Auto Request From Guild"],
							desc = L["Auto Request From Guild Description"],
							type = 'toggle',
							disabled = function() return not IsInGuild() end,
							order = 10,
						}, --[[
						group = { -- TODO: Implement this
							name = L["Auto Request From Group"],
							desc = L["Auto Request From Group Description"],
							type = 'toggle',
							disabled = function() return GetNumPartyMembers() == 0 and GetNumRaidMembers() == 0 end,
							order = 20,
						}, --]]
					}
				},
				manualrequest = {
					name = L["Manual Request"],
					desc = L["Manual Request Description"],
					type = 'group',
					order = 30,
					args = {
						current = {
							name = L["Current Quests"],
							desc = L["Current Quests Description"],
							type = 'group',
							pass = true,
							func = "RequestCurrentQuests",
							order = 10,
							args = {
								guild = {
									name = L["Request From Guild"],
									desc = L["Request From Guild Description"],
									type = 'execute',
									disabled = function() return not IsInGuild() end,
									order = 10,
								},
								group = {
									name = L["Request From Group"],
									desc = L["Request From Group Description"],
									type = 'execute',
									disabled = function() return GetNumPartyMembers() == 0 and GetNumRaidMembers() == 0 end,
									order = 20,
								}
							}
						},
						all = {
							name = L["ALL Quests"],
							desc = L["ALL Quests Description"],
							type = 'group',
							pass = true,
							func = "RequestFullDB",
							order = 20,
							args = {
								guild = {
									name = L["Request From Guild"],
									desc = L["Request From Guild Description"],
									type = 'execute',
									disabled = function() return not IsInGuild() end,
									order = 10,
								},
								group = {
									name = L["Request From Group"],
									desc = L["Request From Group Description"],
									type = 'execute',
									disabled = function() return GetNumPartyMembers() == 0 and GetNumRaidMembers() == 0 end,
									order = 20,
								}
							}
						}
					},
				},
			},
		},
		tracked = {
			name = L["Only Show Tracked"],
			desc = L["Only Show Tracked Description"],
			type = 'toggle',
			get = "GetOnlyShowTracked",
			set = "ToggleOnlyShowTracked",
			order = 55
		},
		hidecompleted = {
			name = L["Hide Completed Objectives"],
			desc = L["Hide Completed Objectives Description"],
			type = 'toggle',
			get = "GetHideCompleted",
			set = "ToggleHideCompleted",
			order = 60
		},
		hideinactive = {
			name = L["Hide Inactive Quests"],
			desc = L["Hide Inactive Quests Description"],
			type = 'toggle',
			get = "GetHideInactive",
			set = "ToggleHideInactive",
			order = 70
		},
		showparty = {
			name = L["Show Party Quests"],
			desc = L["Show Party Quests Description"],
			type = 'toggle',
			get = "GetShowParty",
			set = "ToggleShowParty",
			order = 80
		},
	}
	
	local i = 1
	for k,v in pairs(self.filter) do
		local key,name = k,v
		aceopts.filter.args[key] = {
			name = name,
			desc = name,
			type = 'toggle',
			order = 100 + i,
			get = function()
				return self:IsTypeFilter(key)
			end,
			set = function(value)
				return self:ToggleTypeFilter(key, value)
			end,
		}
		i = i + 1
	end

	Cartographer.options.args["quest objectives"] = {
		name = L["Quest Objectives"],
		desc = L["Module description"],
		type = 'group',
		args = aceopts,
		handler = self,
	}
end

function mod:OnEnable(first)
	if not Cartographer_Notes then
		return Cartographer:ToggleModuleActive(self, false)
	end
	
	if first then
		self:UpgradeDB()
	end
		
	for name,data in pairs(self.icon) do
		Cartographer_Notes:RegisterIcon(name,data)
	end
	
	self:Debug('Cartographer_QuestObjectives enabled')
	
	Cartographer_Notes:RegisterNotesDatabase(DB_NAME, self.db.faction.notes, self)
	
	self:RegisterEvent("Quixote_Leaderboard_Update")
	self:RegisterEvent("Quixote_Party_Leaderboard_Update")
	--self:RegisterEvent("PLAYER_REGEN_DISABLED", "Exit_Combat")
	--self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("TRADE_CLOSED", "Trade_Update")
	self:RegisterEvent("SpecialEvents_ItemLooted")
	
	self:RegisterComm(self.commPrefix, "WHISPER")
	self:RegisterComm(self.commPrefix, "GUILD")
	self:RegisterComm(self.commPrefix, "GROUP")
	--self:RegisterComm(self.commPrefix, "ZONE")
	
	-- Every 30 minutes request a DB dump
	self:ScheduleEvent("autoRequest", self.TimerShare, 1800, self)
	
	Cartographer_Notes:RefreshMap(true)
end

function mod:OnDisable()
	Cartographer_Notes:UnregisterNotesDatabase(DB_NAME)
	for name in pairs(self.icon) do
		Cartographer_Notes:UnregisterIcon(name)
	end

	self:Debug('Cartographer_QuestObjectives disabled')

	Cartographer_Notes:RefreshMap(true)
end

function mod:TimerShare()
	if self:GetAutoRequest("guild") then
		self:RequestFullDB("guild")
	end
end

--------------
-- DB STUFF --
--------------

function mod:UpgradeDB()
	local f = self.db.faction
	
	f.quest_db_version = f.quest_db_version or 1
	
	if f.quest_db_version < QUEST_DB_VERSION then
		local version = f.quest_db_version
		-- Updating version
		for zone,zoneentry in pairs(f.objectives) do
			for quest,questentry in pairs(zoneentry) do
				for objective,objentry in pairs(questentry) do
					-- for each objective...
					if version == 1 then
						-- VERSION 2 CHANGES:
						-- Quest name was not stored explicitly before, now it is. We have to parse it out of the [level] Quest Name format.
						objentry.questname = quest:sub(#tostring(objentry.level)+2)
						objentry.version = QUEST_DB_VERSION
					end
					f.quest_db_version = 2
				end
			end
		end
		if f.quest_db_version > version then
			self:Print(L["Objective database upgraded from version %d to version %d"], version, f.quest_db_version)
		end
	end
end

function mod:ResetSendLimits()
	local objectives = self.db.faction.objectives
	
	for zone,zoneentry in pairs(objectives) do
		for quest,questentry in pairs(zoneentry) do
			for objective,objentry in pairs(questentry) do
				objentry.sent = {}
			end
		end
	end
	
	local notes = self.db.faction.notes
	for zone,zoneentry in pairs(notes) do
		if type(zoneentry) == "table" then
			for noteid, note in pairs(zoneentry) do
				note.sent = {}
			end
		end
	end
	self:Print("All send limits reset.")
end

------------------------
-- Comm Functions --
------------------------

mod.OnCommReceive = {
	REQUEST = function(self, prefix, sender, distribution, zone, quest, level, lid, comm_version)
		-- A player has requested data for a quest. We should respond!
		if not self:GetEnableSharing() then
			self:Debug("Someone (%s) requested notes for a quest, but we have sharing turned off.",sender)
			return
		end
		
		comm_version = comm_version or 1
		
		if type(zone) ~= "string" or type(quest) ~= "string" or type(level) ~= "number" or type(lid) ~= "number" then
			-- bad data
			return
		end
		
		self:Debug("Received a request from %s for notes on quest: [%d] %s in %s",sender,level,quest,zone)
		
		local questdbname = self.FormatQuestDBName(quest,level)
		local questentry = self.db.faction.objectives[zone][questdbname]
		for k,objectiveentry in pairs(questentry) do
			if type(objectiveentry) == "table" and objectiveentry.lid == lid then
				for noteid,nzone in pairs(objectiveentry.notes) do
					--self:Debug("Sending note %d from %s",noteid, nzone)
					self:SendNote(sender,nzone,noteid,comm_version, false, false)
				end
			end
		end
	end,
	
	DBREQUEST = function(self,prefix, sender, distribution, note_version, quest_version, comm_version, locale)
		-- A player has requested a full DB dump.
		
		-- We can't share data if we're on a different locale because the quest names would not match.
		if locale ~= GetLocale() then return end
		
		-- If this was a guild request, we'll only send our own notes.
		local bOnlySendMine = distribution == "GUILD"
		
		self:Debug("Received a FULL DB request from %s. Sending!")
		local questdb = self.db.faction.objectives
		for zone, zoneentry in pairs(questdb) do
			for questdbname, questentry in pairs(zoneentry) do
				for objectivename, objectiveentry in pairs(questentry) do
					if objectiveentry.version == QUEST_DB_VERSION then
						if not objectiveentry.sent[sender] then
							-- Only send this quest if we've never sent it to this player before.
							objectiveentry.sent[sender] = time()
							self:SendQuestObjective(sender, zone, objectiveentry)
						end
						for noteid,nzone in pairs(objectiveentry.notes) do
							-- self:Debug("Sending note %d from %s",noteid, nzone)
							self:SendNote(sender,nzone,noteid,comm_version, true, bOnlySendMine)
						end
					else
						self:Debug("Found an entry with an incorrect version! %s-%s-%s",zone,questdbname,objectivename)
					end
				end
			end
		end
	end,
	
	SENDNOTE = function(self, prefix, sender, distribution, version, compat_version, notezone, x, y, quest, level, lid, count)
		if not self:GetEnableSharing() then
			self:Debug("Someone (%s) tried sending us a note, but we have sharing turned off.",sender)
			return
		end
		
		if type(version) ~= "number" then
			-- bad data
			return
		end
		
		if version < NOTE_DB_COMPAT_VERSION then
			-- version of data is too old
			return
		end
		
		if compat_version > NOTE_DB_VERSION then
			-- version of data sent is newer than what is compatible with this version
			return
		end
		
		if type(notezone) ~= "string"
		or type(x) ~= "number"
		or type(y) ~= "number"
		or type(quest) ~= "string"
		or type(level) ~= "number"
		or type(lid) ~= "number"
		or type(count) ~= "number"
		or x < 0 or x > 1 or y < 0 or y > 1 then
			-- bad data
			return
		end
		
		if BZ:HasTranslation(notezone) then
			notezone = BZ[notezone]
		end
		
		local timer = self.requests[("%d-%s-%d"):format(level,quest,lid)]
		if not timer or timer - time() > 15 then
			-- Check to see if we requested notes for this objective within the last 15 seconds.
			return
		end
		self.requests[("%d-%s-%d"):format(level,quest,lid)] = time()
		
		title, qlevel, _, _, _, _, questzone, questid = quixote:GetQuestByName(quest)
		if not title or qlevel ~= level then return end
		objectivename, objectivetype, _, numNeeded, _ = quixote:GetQuestStatusById(questid, lid)
		
		
		self:Debug("Received note at %.2f,%.2f in %s for objective %d in quest [%d] %s from %s",x,y,notezone,lid,level,quest,sender)
		self:SetNote(notezone, quest, objectivename, x, y, numNeeded, level, lid, objectivetype, sender, count, questzone)
	end,
	
	SENDNOTEF = function(self, prefix, sender, distribution, version, compat_version, notezone, x, y, quest, level, lid, count, questzone)
		if not self:GetEnableSharing() then
			self:Debug("Someone (%s) tried sending us a note, but we have sharing turned off.",sender)
			return
		end
		
		if type(version) ~= "number" then return end
		
		if version < NOTE_DB_COMPAT_VERSION then
			-- version of data is too old
			return
		end
		
		if compat_version > NOTE_DB_VERSION then
			-- version of data sent is newer than what is compatible with this version
			return
		end
		
		if type(notezone) ~= "string"
		or type(x) ~= "number"
		or type(y) ~= "number"
		or type(quest) ~= "string"
		or type(level) ~= "number"
		or type(lid) ~= "number"
		or type(count) ~= "number"
		or type(questzone) ~= "string"
		or x < 0 or x > 1 or y < 0 or y > 1 then
			-- bad data
			return
		end
		
		if BZ:HasTranslation(notezone) then
			notezone = BZ[notezone]
		end
		
		local timer = self.requests[("%d-%s-%d"):format(level,quest,lid)]
		if not timer or timer - time() > 15 then
			-- Check to see if we requested notes for this objective within the last 15 seconds.
			return
		end
		self.requests[("%d-%s-%d"):format(level,quest,lid)] = time()
		
		local questdbname = self.FormatQuestDBName(quest,level)
		local questentry = self.db.faction.objectives[questzone][questdbname]
		
		for k,objectiveentry in pairs(questentry) do
			if type(objectiveentry) == "table" and objectiveentry.lid == lid then		
				self:Debug("Received note at %.2f,%.2f in %s for objective %d in quest [%d] %s from %s",x,y,notezone,lid,level,quest,sender)
				self:SetNote(notezone, quest, objectiveentry.name, x, y, objectiveentry.numNeeded, level, lid, objectiveentry.objectivetype, sender, count, questzone)
				break
			end
		end
	end,
	
	SENDQUEST = function(self, prefix, sender, distribution, zone, quest, objective, numNeeded, level, lid, objectivetype)
		if not self:GetEnableSharing() then
			self:Debug("Someone (%s) tried sending us a db dump, but we have sharing turned off.",sender)
			return
		end
		
		if self:CheckBannedSource(sender) then
			self:Debug("Someone (%s) tried sending us a db dump, but we are ignoring them.", sender)
			return
		end
		
		if type(zone) ~= "string"
		or type(quest) ~= "string"
		or type(objective) ~= "string"
		or type(numNeeded) ~= "number"
		or type(level) ~= "number"
		or type(lid) ~= "number"
		or type(objectivetype) ~= "string" then
			-- bad data
			return
		end
		
		if BZ:HasTranslation(zone) then
			zone = BZ[zone]
		end
		
		local timer = self.requests["fulldb"]
		if not timer or timer - time() > 15 then
			-- Check to see if we requested notes for this objective within the last 15 seconds.
			return
		end
		self.requests["fulldb"] = time()
		
		-- Fake a request timer for this quest, because notes will be coming through soon.
		-- Ew gross hacks.
		self.requests[("%d-%s-%d"):format(level,quest,lid)] = time()+10
		
		self:RegisterQuestObjective(zone, quest, objective, numNeeded, level, lid, objectivetype, 0, sender)
	end
}

function mod:SendQuestObjective(player, zone, entry)
	self:Debug("Sending quest info for [%q] %s in %s", entry.level, entry.questname, zone)
	self:SendCommMessage("WHISPER", player, "SENDQUEST",zone,entry.questname,entry.name,entry.numNeeded,entry.level,entry.lid,entry.objectivetype)
end

function mod:SendNote(player, notezone, noteid, comm_version, bFull, bOnlyMine)
	local x,y = Cartographer_Notes.getXY(noteid)
	
	local zoneentry = self.db.faction.notes[notezone]
	if not zoneentry then return end
	local data = zoneentry[noteid]
	if not data then return end
	
	-- Obviously we do not want to send notes that we received from this very player!
	if data.sender == player then return end
	
	if bOnlyMine and data.sender ~= "self" then return end
	
	-- Check if we have sent this note to this player before. If we have then don't send it!
	if not data.sent then data.sent = {} end
	if data.sent[player] then return end
	data.sent[player] = time()
	
	if bFull then
		self:SendCommMessage("WHISPER",player,"SENDNOTEF",data.version,NOTE_DB_COMPAT_VERSION,notezone,x,y,data.quest,data.level,data.lid,data.count, data.questzone)
	else
		self:SendCommMessage("WHISPER",player,"SENDNOTE",data.version,NOTE_DB_COMPAT_VERSION,notezone,x,y,data.quest,data.level,data.lid,data.count)
	end
end


function mod:OnNoteReceive(zone, x, y, icon, creator, data, sender, fullSender)
	--We do not want notes to be sent using Cartographer_Notes. This simply rejects them.
	--Maybe in the future I'll convert the note to the proper format and allow it to be sent this way.
	return true
end

function mod:RequestNotes(zone,quest,level,lid, dist)
	if dist == "guild" then dist = "GUILD"
	elseif dist == "group" then dist = "GROUP"
	end
	
	if not BZ:HasTranslation(zone) then
		if BZ:HasReverseTranslation(zone) then
			zone = BZ:GetReverseTranslation(zone)
		else
			--This isn't fatal since doing the localizing won't really help anyway.
			--error(("Trying to request notes for a quest in an unknown zone: %q"):format(zone), 2)
		end
	end
	
	self.requests[("%d-%s-%d"):format(level,quest,lid)] = time()
	
	self:Debug("Sending request to %s for objective %d from [%d] %s in %s",dist,lid,level,quest,zone)
	
	self:SendCommMessage(dist,"REQUEST",zone,quest,level,lid, COMM_VERSION)
end

function mod:RequestCurrentQuests(dist)
	local quests = self.db.faction.objectives
	
	self:Debug("Requesting quest objective notes for ALL quests",zone)
	
	for k, zone in quixote:IterZones() do
		self:Debug("Checking quests in %s",zone)
		local zonequests = quests[zone]
		for i, questid in quixote:QuestsByZone(zone) do
			local questname, questlevel, _, _, _, numObjectives, _, _ = quixote:GetQuest(questid)
			--self:Debug("Checking details for quest %s",questname)
			if numObjectives > 0 then
				local questdbname = self.FormatQuestDBName(questname,questlevel)
				local questentry = zonequests and zonequests[questdbname]
				for j=1,numObjectives do
					local description, otype, numGot, numNeeded, done = quixote:GetQuestStatusById(questid, j)
					--self:Debug("Checking details for objective %s",description)
					if otype ~= 'reputation' then
						local objectiveentry = questentry and questentry[description]
						if objectiveentry and objectiveentry.count and objectiveentry.count >= numNeeded then
							self:Debug("Did not request objective %s for quest %s in %s because we already have enough notes.",description,questname,zone)
						else
							self:RequestNotes(zone,questname,questlevel,j,dist)
						end
					end
				end
			end
		end
	end
end

function mod:RequestFullDB(dist)
	if dist == "guild" then dist = "GUILD"
	elseif dist == "group" then dist = "GROUP"
	end
	
	self:Debug("Requesting full database dump from %s!", dist)
	
	self.requests["fulldb"] = time()
	
	self:SendCommMessage(dist,"DBREQUEST", NOTE_DB_VERSION, QUEST_DB_VERSION, COMM_VERSION, GetLocale())
end

------------------------
-- Events --
------------------------

--[[ CURRENTLY UNUSED
function mod:Exit_Combat()
	self.timers['combat']['player'] = time()
end
--]]

function mod:Trade_Update()
	--TODO: Test this, might need more hooks to be sure they fire before the quest is updated
	self.timers['playertrade'] = time()
	self:Debug('TRADE_UPDATE')
end

function mod:SpecialEvents_ItemLooted(who)
	-- This is our best guess to figure out if someone actually looted a quest item as opposed to got it from a trade.
	local unitid = roster:GetUnitIDFromName(who)
	if not unitid then return end
	if unitid == 'player' then return end
	self.timers['loot'][unitid] = time()
end

function mod:CheckObjectiveValid(unit, otype, description)
	if unit ~= 'player' and time() - self.timers['playerobjective'] < 4 and description == self.lastobjective then return false end

	if otype == 'item' then
		if unit == 'player' and time() - self.timers['playertrade'] < 4 then return false end	
		if unit ~= 'player' and time() - self.timers['loot'][unit] > 4 then return false end
	elseif otype == 'monster' then
		-- This doesn't work very well because there are some 'monster' quests where you don't fight.
		--if not UnitAffectingCombat(unit) and time() - self.timers['combat'][unit] > 3 then return false end
	end
	
	
	return true
end

function mod:Quixote_Leaderboard_Update(name, id, lid, desc, numHad, numGot, numNeeded)
	Cartographer_Notes:RefreshMap(true)
	
	local count = numGot - numHad
	if count < 0 then return end -- If the player destroyed a quest objective, we don't want to create a note!
	
	local title, level, tag, suggestedGroup, complete, numObjectives, questzone, questid = quixote:GetQuest(id)
	local description, otype = quixote:GetQuestStatusById(id, lid)
	
	--self:Debug(('%s %d %d %s %d %d %d'):format(name, id, lid, desc, numHad, numGot, numNeeded))
	--self:Debug(('%s %d %s %d %s %d %s'):format(title, level, tag, numObjectives, questzone, questid, otype))
	
	if otype == 'reputation' then return end -- Reputation quests don't have a particular location
	
	if not self:CheckObjectiveValid('player',otype, desc) then return end
	
	self.timers['playerobjective'] = time()
	self.lastobjective = desc
	
	local zone = GetRealZoneText()
	local x, y = Cartographer:GetCurrentPlayerPosition()
	if x==0 or y==0 then return end
	
	self:SetNote(zone, title, desc, x, y, numNeeded, level, lid, otype, "self", count, questzone)
end

function mod:Quixote_Party_Leaderboard_Update(sender, name, desc, numHad, numGot, numNeeded)
	Cartographer_Notes:RefreshMap(true)
	
	local count = numGot - numHad
	if count < 0 then return end -- If the player destroyed a quest objective, we don't want to create a note!
	
	local title, level, tag, suggestedGroup, complete, numObjectives, questzone, questid = quixote:GetQuest(name)
	
	if not questid then return end -- If the player does not have this quest, we can't add a note because we need more details, like the leaderboard id
	
	local bFound = false
	local description, otype
	local lid
	for i=1, numObjectives do
		description, otype = quixote:GetQuestStatusById(questid, i)
		if description==desc then
			bFound = true
			lid = i
			break
		end
	end
	if not bFound then return end -- We couldn't find the objective for some reason
	
	--self:Debug('Party Leaderboard Update')
	--self:Debug(('%s %s %d %s %d %d %d'):format(sender, name, questid, description, numHad, numGot, numNeeded))
	--self:Debug(('%s %d %s %d %s %d'):format(title, level, tag, numObjectives, zone, questid))
	
	if otype == 'reputation' then return end -- Reputation quests don't have a particular location
	
	local unitid = roster:GetUnitIDFromName(sender)
	if not unitid then return end
	
	if not self:CheckObjectiveValid(unitid,otype,desc) then return end
	
	SetMapToCurrentZone()
	local zone = GetRealZoneText()
	local x, y = GetPlayerMapPosition(unitid)
	if x==0 or y==0 then return end
	
	self:SetNote(zone, title, desc, x, y, numNeeded, level, lid, otype, "self", count, questzone)
end

function mod.FormatQuestFriendlyName(name,level)
	return ('[%d] %s'):format(level,name)
end

function mod.FormatQuestDBName(name,level)
	return ('%d-%s'):format(level,name)
end

function mod:CheckBannedSource(source)
	return self.db.faction.ignorelist[source]==true
end


function mod:SetNote(zone, questname, objectivename, x, y, numNeeded, questlevel, lid, objectivetype, sender, count, questzone)
	if x == nil or x == 0 and y == 0 then return end
	
	if sender ~= "self" and self:CheckBannedSource(sender) then
		self:Debug("Not adding note because this source (%s) is being ignored.",sender)
		return
	end
	
	-- Check for nearby note for same objective
	for _zone,_x,_y,_icon,_db,data in Cartographer_Notes:IterateNearbyNotes(zone, x, y, 75, DB_NAME, nil, true) do
		if _db == DB_NAME and data.quest == questname and data.info == objectivename then
			if not data.count then data.count = 0 end
			if sender == "self" then
				-- We only up the count if it's our own note. This is to prevent the exact same note
				-- being received via comm constantly increasing the count. There is probably a better way
				-- to do this...
				data.count = data.count + count
			else
				-- If it's not our note, then we'll just up the count to the sent count
				local diff = count - data.count
				if diff > 0 then data.count = count end
				count = math.max(0,diff)
			end
			return
		end
	end
	
	if not self:RegisterQuestObjective(questzone, questname, objectivename, numNeeded, questlevel, lid, objectivetype, count, sender) then
		self:Debug("Not adding note because this objective is being ignored.")
		return
	end
	
	local noteid = Cartographer_Notes:SetNote(zone, x, y, ICON_NAME, DB_NAME,
		'title', self.FormatQuestFriendlyName(questname,questlevel,objectivename),
		'quest', questname,
		'level', questlevel,
		'version', NOTE_DB_VERSION,
		'numneeded', numNeeded,
		'info', objectivename,
		'objectivetype', objectivetype,
		'lid', lid,
		'count', count,
		'sender', sender,
		'questzone',questzone
	)
	
	if noteid then
		self:RegisterNoteToQuest(zone, questname, objectivename, questlevel, x, y, questzone)
		if sender ~= "self" then
			self:RegisterNoteToSource(sender, zone, x, y)
		end
	end
end

function mod:RegisterQuestObjective(zone, questname, objectivename, numNeeded, questlevel, lid, objectivetype, count, sender)
	local questdbname = self.FormatQuestDBName(questname,questlevel)
	local entry = self.db.faction.objectives[zone][questdbname][objectivename]
	if not entry then
		self:Debug('New objective: %q from %q in %q', objectivename, questname, zone)
		entry = {}
		self.db.faction.objectives[zone][questdbname][objectivename] = entry
	elseif entry.ignore == true then
		return false
	end
	entry.name    		= objectivename
	entry.level		= questlevel
	entry.lid       	= lid
	entry.objectivetype	= objectivetype
	entry.numNeeded       	= numNeeded
	entry.questname 	= questname
	entry.version		= QUEST_DB_VERSION
	if not entry.notes then entry.notes = {} end
	if not entry.sent then entry.sent = {} end
	if sender ~= "self" then
		entry.sent[sender] = time()
	end
	if entry.count then entry.count = entry.count + count
	else entry.count = count end
	
	return true
end

function mod:RegisterNoteToQuest(zone, questname, objectivename, questlevel, x, y, questzone)
	local questdbname = self.FormatQuestDBName(questname,questlevel)
	local entry = self.db.faction.objectives[questzone][questdbname][objectivename]
	if not entry then
		-- This shouldn't ever happen because we register the objective before we try to do this...
		return false
	end
	
	local noteid = Cartographer_Notes.getID(x,y)
	entry.notes[noteid] = zone
end

function mod:RegisterNoteToSource(source, zone, x, y)
	local sourcedb = self.db.faction.sources[source]
	if not sourcedb then
		sourcedb = {}
		self.db.faction.sources[source] = sourcedb
	end
	
	local noteid = Cartographer_Notes.getID(x,y)
	sourcedb[noteid] = zone
end


------------------------
-- Note API overrides --
------------------------

function mod:GetNoteTransparency(zone,id,data)
	return self:GetIconAlpha()
end

function mod:GetNoteScaling(zone,id,data)
	if not data.count then data.count = 1 end
	
	local scale = data.count/data.numneeded
	scale = math.min(scale,1)
	
	return self:GetIconScale()*(scale+1)
end

function mod:GetDifficultyColor(playerlevel,targetlevel)
	if targetlevel == -1 then return 'red' end
	
	local diff = targetlevel-playerlevel
	if diff >= 5 then
		return 'red'
	elseif diff >= 3 then
		return 'orange'
	elseif diff >= -2 then
		return 'yellow'
	elseif diff >= -5 then
		return 'green'
	else
		return 'gray'
	end
end

function mod:GetNoteIcon(zone, id, data)
	if self:GetUseObjectiveIcons() and data.objectivetype then
		return ICON_NAME.."-"..data.objectivetype
	else
		if self:GetColorIcons() then
			local difficulty = self:GetDifficultyColor(UnitLevel('player'), data.level)
			return ICON_NAME.."-"..difficulty
		else
			return ICON_NAME.."-green"
		end
	end
	
	return ICON_NAME
end

function mod:IsPartyOnQuest(quest)
	for i=1, GetNumPartyMembers() do
		local name = UnitName('party'..i)
		if quixote.party[name] and quixote.party[name][quest] then
			return true
		end
	end
	return false
end

function mod:IsPartyAllDone(quest,objective,numneeded)
	for i=1, GetNumPartyMembers() do
		local name = UnitName('party'..i)
		local n = quixote:GetPartyQuestStatus(name, quest, objective)
		if n and n < numneeded then
			return false
		end
	end
	return true
end

function mod:IsNoteHidden(zone, id, data)
	local _, level, _, _, _, _, _, questid = quixote:GetQuestByName(data.quest)
	
	if not self:IsTypeFilter(data.objectivetype) then return true end
	
	if questid and level and level == data.level then
		local description, otype, _, _, done = quixote:GetQuestStatusById(questid, data.lid)
		
		if self:GetOnlyShowTracked() and not IsQuestWatched(questid) then
			return true
		end
		
		if self:GetHideCompleted() and done and (not self:GetShowParty() or self:IsPartyAllDone(data.quest,data.info,data.numneeded)) then
			return true
		end
	else
		if self:GetOnlyShowTracked() then return true end
		
		if self:GetHideInactive() then
			if not self:GetShowParty() then
				return true
			elseif not self:IsPartyOnQuest(data.quest) then
				return true
			elseif self:GetHideCompleted() and self:IsPartyAllDone(data.quest,data.info,data.numneeded) then
				return true
			end
		end
	end
	
	return false
end

function mod:GetObjectiveCompleteness(questname,questlevel,lid)
	local title, level, tag, suggestedGroup, complete, numObjectives, zone, questid = quixote:GetQuestByName(questname)
	if level and level == questlevel then
		local description, otype, numGot, numNeeded, done = quixote:GetQuestStatusById(questid, lid)
		return numGot
	else
		return nil
	end
end

local yardString = L["%.0f yd"]

function mod:OnNoteTooltipRequest(zone, id, data, inMinimap)

	local thisQuestColor = GetDifficultyColor(data.level)
	
	Tablet:SetTitle(data.title)
	Tablet:SetTitleColor(thisQuestColor.r,thisQuestColor.g,thisQuestColor.b)
	

	local cat = Tablet:AddCategory(
		'text', L['Quest Objectives'],
		'columns', 2,
		'wrap', true,
		'justify2',
		'RIGHT'
	)
	
	local numGot = self:GetObjectiveCompleteness(data.quest,data.level,data.lid)
	local numNeeded = data.numneeded
	local party = ''
	for i=1, GetNumPartyMembers(), 1 do
		local unit = 'party'..i
		local n = quixote:GetPartyQuestStatus(unit, data.quest, data.info)
		if n and type(n) == 'number' then
			if n == numNeeded then n = 'd' end
			party = string.format("%s|c00%s%s:%s|r ", party, babbleclass:GetHexColor(UnitClass(unit)), string.sub(UnitName(unit), 1, 3), n)
		end
	end
	local player = ''
	local r,g,b
	if numGot then
		player = numGot==data.numneeded and L["(done)"] or string.format("%s/%s", numGot, numNeeded)
		r,g,b = crayon:GetThresholdColor(numGot/numNeeded)
	else
		player = L['N/A']
	end
	
	cat:AddLine(
		'text', data.info,
		'text2', party .. player,
		--'textR', r or 1, 'textG', g or 1, 'textB', b or 1,
		'text2R', r or 1, 'text2G', g or 1, 'text2B', b or 1
		--'size', fontSize, 'size2', fontSize,
		--'arg2', questid,
		--'indentation', indent
	)
	
	local l = L['ObjectiveTypes']
	cat = Tablet:AddCategory(
		'columns', 2,
		'hideBlankLine', true
	)
	cat:AddLine(
		'text', L['Objective Type'],
		'text2', l[data.objectivetype]
	)
	if data.sender ~= "self" then
		cat:AddLine(
			'text', L['Source'],
			'text2', data.sender
		)
	end
	
	-- Riped from Cartograhper_Notes
	if not this.minimap and Cartographer_Notes:IsShowingYardsAway() then
		local x, y = Cartographer_Notes.getXY(tonumber(id))
		local dist = Cartographer:GetDistanceToPoint(x, y, zone)
		if dist then
			Tablet:AddCategory(
				'columns', 2,
				'hideBlankLine', true
			):AddLine(
				'text', Cartographer.L["Distance:"],
				'text2', yardString:format(dist)
			)
		end
	end
	if not this.minimap and Cartographer_Notes:IsShowingCreator() then
		Tablet:AddCategory(
			'columns', 2,
			'hideBlankLine', true
		):AddLine(
			'text', Cartographer_Notes.L["Created by"],
			'text2', L["Quest Objectives"]
		)
	end

end

function mod:OnNoteMenuRequest(zone, id, data, level, value, level2, level3, level4, defaultMenu)

	local function isWaypointFunc()
		return Cartographer_Waypoints:IsNoteWaypoint(id..zone)
	end
	local function waypointFunc()
		if isWaypointFunc() then
			Cartographer_Waypoints:CancelWaypoint(id..zone)
		else
			Cartographer_Waypoints:SetNoteAsWaypoint(zone, id)
		end
		Dewdrop:Close()
	end
	local function closeMenu()
		Dewdrop:Close()
	end

	if level == 1 then
		Dewdrop:AddLine(
			'text', L['Delete'],
			'hasArrow', true,
			'value', 'delete'
		)
		Dewdrop:AddLine()
		
		-- Ripped from Cartographer_Notes
		if Cartographer_Waypoints and Cartographer:IsModuleActive(Cartographer_Waypoints) then -- and BZ[poi.zone] == GetRealZoneText() then
			Dewdrop:AddLine(
				'text', Cartographer_Notes.L["Set as waypoint"],
				'func', waypointFunc,
				'checked', isWaypointFunc()
			)
			Dewdrop:AddLine()
		end

		Dewdrop:AddLine(
			'text', CANCEL,
			'func', closeMenu
		)
		-- End Ripped from Cartographer_Notes
		
	elseif level == 2 and value == 'delete' then
	
		Dewdrop:AddLine(
			'text', L['This Note'],
			'hasArrow', true,
			'value', 'deletethisnote'
		)
		
		Dewdrop:AddLine(
			'text', L['All for This Objective'],
			'hasArrow', true,
			'value', 'deleteallobjective',
			'tooltipTitle', L['All for This Objective'],
			'tooltipText', L['All for This Objective Description']
		)
		
		Dewdrop:AddLine(
			'text', L['All for This Objective Forever'],
			'hasArrow', true,
			'value', 'deleteallobjectiveforever',
			'tooltipTitle', L['All for This Objective Forever'],
			'tooltipText', L['All for This Objective Forever Description']
		)
		
		if data.sender and data.sender ~= "self" then
			Dewdrop:AddLine(
				'text', L['All from %s']:format(data.sender),
				'hasArrow', true,
				'value', 'deleteallsource',
				'tooltipTitle', L['All From This Source'],
				'tooltipText', L['All From This Source Description']
			)
			
			Dewdrop:AddLine(
				'text', L['All from %s Forever']:format(data.sender),
				'hasArrow', true,
				'value', 'deleteallsourceforever',
				'tooltipTitle', L['All From This Source Forever'],
				'tooltipText', L['All From This Source Forever Description']
			)
		end

	elseif level == 3 and value:sub(1,6) == 'delete' then
		
		local deletewhat = value:sub(7)
		
		Dewdrop:AddLine(
			'text', L['Confirm Delete'],
			'textR', 1, 'textG', 0, 'textB', 0,
			'tooltipTitle', L['Confirm Delete'],
			'tooltipText', L['WARNING: THIS IS NOT UNDOABLE.'],
			'func', function()
				self:DeleteNotes(zone, id, data, deletewhat)
				Dewdrop:Close()
			end
		)
		
	else
		defaultMenu(level, value, level2, level3, level4)	
	end
end

function mod:DeleteNotes(zone, id, data, deletewhat)
	local notedb = self.db.faction.notes
	local objectivedb = self.db.faction.objectives
	local questdbname = self.FormatQuestDBName(data.quest,data.level)
	local numdeleted = 0
	
	self:Debug(deletewhat)
	
	if deletewhat == 'thisnote' then
		if data.questzone then
			local notesentry = objectivedb[data.questzone][questdbname][data.info]['notes']
			if notesentry then
				notesentry[id] = nil
			end
		end
	
		local zoneentry = notedb[zone]
		if zoneentry then
			zoneentry[id] = nil
		end
		
		numdeleted = numdeleted + 1
	elseif deletewhat:sub(1,12) == 'allobjective' then
		local forever = deletewhat:sub(13) == 'forever'
		local objectiveentry = objectivedb[data.questzone][questdbname][data.info]
		local notesentry = objectiveentry['notes']
		
		if notesentry then
			for noteid,notezone in pairs(notesentry) do
				local zoneentry = notedb[zone]
				if zoneentry then
					local data = zoneentry[noteid]
					if data.sender and data.sender ~= 'self' then
						local sourcedb = self.db.faction.sources[data.source]
						if sourcedb then
							sourcedb[noteid] = nil
						end
					end
					zoneentry[noteid] = nil
					numdeleted = numdeleted + 1
				end
				
				notesentry[noteid] = nil
			end
			objectiveentry.count = 0
			if forever then
				objectiveentry.ignore = true
			end
		end
	elseif deletewhat:sub(1,9) == 'allsource' then
		local forever = deletewhat:sub(10) == 'forever'
		if data.sender and data.sender ~= 'self' then
			local sourcedb = self.db.faction.sources[data.sender]
			if sourcedb then
				for noteid, zone in pairs(sourcedb) do
					if notedb[zone] and notedb[zone][noteid] then -- purple
						local data = notedb[zone][noteid] -- purple
						local questdbname = self.FormatQuestDBName(data.quest,data.level)
						local objectiveentry = objectivedb[data.questzone][questdbname][data.info]
						local objectivenotesentry = objectiveentry['notes']
						if objectivenotesentry then
							objectivenotesentry[noteid] = nil
						end
						
						if objectiveentry.count and data.count then
							objectiveentry.count = objectiveentry.count - data.count
						end
						
						notedb[zone][noteid] = nil
						numdeleted = numdeleted + 1
					end
					sourcedb[noteid] = nil
					if forever then
						self.db.factions.ignorelist[data.sender] = true
					end
				end
			end
		end
	end
	
	Cartographer_Notes:RefreshMap(true)
	if numdeleted == 1 then
		self:Print(L["%d note has been deleted!"]:format(numdeleted))
	else
		self:Print(L["%d notes have been deleted!"]:format(numdeleted))
	end
end


--------------
-- Settings --
--------------


function mod:IsTypeFilter(filtertype)
	return self.db.profile.filter[filtertype]
end

function mod:ToggleTypeFilter(filtertype, value)
	if value == nil then
		value = not self.db.profile.filter[filtertype]
	end
	self.db.profile.filter[filtertype] = value

	return Cartographer_Notes:RefreshMap(true)
end


function mod:GetUseObjectiveIcons()
	return self.db.profile.useObjectiveIcons
end

function mod:ToggleUseObjectiveIcons()
	self.db.profile.useObjectiveIcons = not self.db.profile.useObjectiveIcons
	Cartographer_Notes:RefreshMap(true)
end


function mod:GetColorIcons()
	return self.db.profile.colorIcons
end

function mod:ToggleColorIcons()
	self.db.profile.colorIcons = not self.db.profile.colorIcons
	Cartographer_Notes:RefreshMap(true)
end


function mod:GetOnlyShowTracked()
	return self.db.profile.onlyShowTracked
end

function mod:ToggleOnlyShowTracked()
	self.db.profile.onlyShowTracked = not self.db.profile.onlyShowTracked
	Cartographer_Notes:RefreshMap(true)
end

function mod:GetHideCompleted()
	return self.db.profile.hideCompleted
end

function mod:ToggleHideCompleted()
	self.db.profile.hideCompleted = not self.db.profile.hideCompleted
	Cartographer_Notes:RefreshMap(true)
end

function mod:GetHideInactive()
	return self.db.profile.hideInactive
end

function mod:ToggleHideInactive()
	self.db.profile.hideInactive = not self.db.profile.hideInactive
	Cartographer_Notes:RefreshMap(true)
end

function mod:GetShowParty()
	return self.db.profile.showParty
end

function mod:ToggleShowParty()
	self.db.profile.showParty = not self.db.profile.showParty
	Cartographer_Notes:RefreshMap(true)
end



function mod:IsShowingMinimapIcons()
	return self.db.profile.minimapIcons
end

function mod:ToggleShowingMinimapIcons()
	self.db.profile.minimapIcons = not self.db.profile.minimapIcons
end

function mod:IsMiniNoteHidden(zone,id,data)
	return not self.db.profile.minimapIcons
end

function mod:GetIconScale()
	return self.db.profile.iconScale
end

function mod:SetIconScale(value)
	self.db.profile.iconScale = value
	Cartographer_Notes:RefreshMap(true)
end
function mod:GetIconAlpha()
	return self.db.profile.iconAlpha
end

function mod:SetIconAlpha(value)
	self.db.profile.iconAlpha = value
	Cartographer_Notes:RefreshMap(true)
end



function mod:GetEnableSharing()
	return self.db.profile.enableSharing
end

function mod:ToggleEnableSharing()
	self.db.profile.enableSharing = not self.db.profile.enableSharing
end

function mod:GetAutoRequest(category)
	return self.db.profile.autoRequest[category]
end

function mod:ToggleAutoRequest(category)
	self.db.profile.autoRequest[category] = not self.db.profile.autoRequest[category]
end